<?php

namespace App\Http\Services\CoolNumberShoppingMall;

use App\Exceptions\PublicException;
use App\Http\Model\CoolNumberShoppingMall\CoolNumber;
use App\Http\Model\CoolNumberShoppingMall\GoodsTag;
use App\Http\Model\CoolNumberShoppingMall\Order;
use App\Http\Model\CoolNumberShoppingMall\OrderLog;
use App\Http\Model\CoolNumberShoppingMall\ShoppingMallGoods;
use App\Http\Model\CoolNumberShoppingMall\UserScore;
use App\Http\Model\CoolNumberShoppingMall\UserScoreStream;
use App\Http\Model\User;
use App\Http\Services\CommonPrivateMsgServices;
use App\Http\Services\CommonServices;
use App\Http\Services\CommonSystemMsgServices;
use App\Http\Services\GoodsLevelServices;
use App\Http\Traits\DelayTask;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class ShoppingMallGoodsServices extends CommonServices
{
    use DelayTask;

    /**
     * @var ShoppingMallGoods
     */
    private $modelGoods;

    /**
     * @var CoolNumber
     */
    private $modelCoolNumber;

    /**
     * @var User
     */
    private $modelUser;

    /**
     * @var Order
     */
    private $modelOrder;

    /**
     * @var UserScore
     */
    private $modelUserScore;

    /**
     * @var OrderLog
     */
    private $modelOrderLog;

    /**
     * @var CommonSystemMsgServices
     */
    private $serviceSystemMsg;

    /**
     * @var CommonPrivateMsgServices
     */
    private $servicePrivateMsg;

    /**
     * 构造函数
     */
    public function __construct()
    {
        parent::__construct();
        $this->modelGoods = new ShoppingMallGoods();
        $this->modelCoolNumber = new CoolNumber();
        $this->modelUser = new User();
        $this->modelOrder = new Order();
        $this->modelUserScore = new UserScore();
        $this->modelOrderLog = new OrderLog();
        $this->serviceSystemMsg = new CommonSystemMsgServices();
        $this->servicePrivateMsg = new CommonPrivateMsgServices();
    }

    /**
     * 添加/编辑商品商品
     *
     * Created at 2021/12/6 18:17
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param array $params
     * @throws PublicException
     */
    public function addAndUpdate(array $params)
    {
        $params['user_can_buy'] = $this->checkUserCanBuy($params['cool_number_id'] ?? 0);//用户是否可购买
        $id = $params['id'] ?? 0;
        unset($params['id']);
        $params['updated_at'] = time();
        if ($params['effective_time'] == 1) {
            $params['effective_time'] = 360;// 方便测试，5分钟
        } else {
            $params['effective_time'] = $params['effective_time'] * 24 * 3600;// 把天转化为秒
        }

        if ($id) {
            unset($params['cool_number_id'], $params['effective_time']);// 这两个值不能更新
            $this->modelGoods->singleUpdate(['id' => $id], $params);
        } else {
            if (!$params['user_can_buy']) {
                throw new PublicException('靓号已被使用');
            }

            if ($this->modelGoods->getTotalNumberOfQuery(['cool_number_id' => $params['cool_number_id']])) {
                throw new PublicException('靓号商品已存在');
            }

            $params['user_can_buy_time'] = 0;
            $params['created_at'] = time();
            $this->modelGoods->insertSingle($params);
        }
    }

    /**
     * 检测用户能否购买该靓号
     *
     * Created at 2021/12/6 18:55
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $coolNumberId
     * @return int
     */
    private function checkUserCanBuy(int $coolNumberId): int
    {
        $yes = ShoppingMallGoods::USER_CAN_BUY_YES;
        $no = ShoppingMallGoods::USER_CAN_BUY_NO;
        if (!$coolNumberId) {
            return $no;
        }

        $uuid = strval($this->modelCoolNumber->getSingleValue(['id' => $coolNumberId], 'uuid'));
        if (!$uuid) {//记录不存在
            return $no;
        }

        $query = $this->modelUser->getTotalNumberOfQueryRaw('uuid="' . $uuid . '"');
        if ($query) {//已有用户在使用
            return $no;
        }

        $query = $this->modelOrder->getTotalNumberOfQueryRaw('uuid="' . $uuid . '" and expiry_time>' . time());
        if ($query) {//其他用户已购买，且未过期
            return $no;
        }

        return $yes;
    }

    /**
     * 后台-商品列表
     *
     * Created at 2021/12/6 19:04
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param Request $request
     * @return array
     */
    public function search(Request $request)
    {
        $data = [];
        $page = intval($request->input('page', 0));//第1页传0
        $pageSize = intval($request->input('limit', 10));//每页多少条
        $data['page'] = $page <= 0 ? 1 : $page;
        $data['limit'] = $pageSize <= 0 ? 10 : $pageSize;
        $data['total'] = ShoppingMallGoods::query()->count();
        $data['list'] = [];
        $data['page_total'] = 1;
        if (!$data['total']) {
            return $data;
        }

        $start = ($data['page'] - 1) * $data['limit'];
        $data['list'] = ShoppingMallGoods::query()->limit($data['limit'])->offset($start)
            ->orderByDesc('id')->get()->toArray();
        $data['page_total'] = intval(ceil($data['total'] / $data['limit']));
        $coolNumberIds = array_column($data['list'], 'cool_number_id');
        $uuids = collect(CoolNumber::query()->select(['id', 'uuid'])->whereIn('id', $coolNumberIds)->get()->toArray())->keyBy('id')->toArray();


        /*$levelResule = (new GoodsLevelServices())->getGoosLevelList([]);
        $level = [];
        if ($levelResule && $levelList =$levelResule['data']){
            $level = array_column($levelList, NULL, 'level');
        }*/

        foreach ($data['list'] as &$item) {
            $item['is_show_tip'] = $item['is_show'] == ShoppingMallGoods::IS_SHOW_YES ? '展示' : '不展示';
            $item['effective_time_tip'] = intval($item['effective_time'] / (24 * 3600));
            $item['uuid'] = $uuids[$item['cool_number_id']]['uuid'] ?? '';
            //$level_info = $level[$item['level']] ?? [];
            //$item['level_info'] = (object) $level_info;
        }

        return $data;
    }

    /**
     * app段靓号商品列表
     *
     * Created at 2021/12/6 19:14
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param Request $request
     * @return array
     */
    public function listGoods(Request $request)
    {
        $data = [];
        $page = intval($request->input('page', 0));//第1页传0
        $pageSize = intval($request->input('pageSize', 10));//每页多少条
        $data['page'] = $page < 0 ? 0 : $page;
        $data['limit'] = $pageSize <= 0 ? 10 : $pageSize;
        $where = ['is_show' => ShoppingMallGoods::IS_SHOW_YES];
        $data['total'] = ShoppingMallGoods::query()->where($where)->count();
        $data['list'] = [];
        $data['page_total'] = 1;
        if (!$data['total']) {
            return $data;
        }

        $start = $data['page'] * $data['limit'];
        $data['list'] = ShoppingMallGoods::query()->where($where)->limit($data['limit'])->offset($start)->orderByDesc('weight')
            ->orderByDesc('id')->get()->toArray();
        $data['page_total'] = intval(ceil($data['total'] / $data['limit']));
        $tags = collect((new GoodsTag())->getTagsByIds(array_column($data['list'], 'tag_id')))->keyBy('id')->toArray();

        $levelResule = (new GoodsLevelServices())->getGoosLevelList([]);
        $level = [];
        if ($levelResule && $levelList =$levelResule['data']){
            $level = array_column($levelList, NULL, 'level');
        }
        foreach ($data['list'] as &$item) {
            $item['goods_id'] = $item['id'];
            $item['goods_image'] = getFullImageUrl($item['goods_image']);
            $item['tag_name'] = $tags[$item['tag_id']]['tag_name'] ?? '';
            $item['tag_image'] = isset($tags[$item['tag_id']]) ? getFullImageUrl($tags[$item['tag_id']]['tag_image']) : '';
            $item['effective_time_day'] = intval($item['effective_time'] / (24 * 3600));
            $level_info = $level[$item['level']] ?? [];
            $item['level_info'] = (object)$level_info;
            unset($item['user_can_buy'], $item['cool_number_id'], $item['effective_time'], $item['tag_id'],
                $item['is_show'], $item['weight'], $item['created_at'], $item['updated_at'], $item['id']);
        }

        return $data;
    }

    /**
     * 检测是否能购买
     *
     * Created at 2021/12/7 19:41
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $buyerUserId
     * @param int $goodsId
     * @param int $toUserId
     * @return array
     * @throws PublicException
     */
    private function checkGoods(int $buyerUserId, int $goodsId, int $toUserId = 0): array
    {
        $goods = $this->modelGoods->getSingle(['id' => $goodsId],
            ['id', 'goods_name', 'can_buy', 'user_can_buy', 'price', 'effective_time', 'cool_number_id', 'price', 'is_show', 'goods_image'], true);
        if (!$goods) {
            throw new PublicException('商品不存在');
        }

        if ($goods['can_buy'] == ShoppingMallGoods::CAN_BUY_NO || $goods['is_show'] == ShoppingMallGoods::IS_SHOW_NO) {
            throw new PublicException('该商品不能被兑换或赠送');
        }

        if ($goods['user_can_buy'] == ShoppingMallGoods::USER_CAN_BUY_NO) {
            throw new PublicException('手慢了，已经被别人抢走了~');
        }

        $userScore = $this->modelUserScore->getUserScore($buyerUserId);
        if ($userScore < $goods['price']) {
            throw new PublicException('积分不足，可通过官方活动获得');
        }

        $uuid = $this->modelCoolNumber->getSingleValue(['id' => $goods['cool_number_id']], 'uuid');
        if (!$uuid) {
            throw new PublicException('商品不存在');
        }

        $goods['uuid'] = $uuid;
        return $goods;
    }

    /**
     * 购买或赠送靓号
     *
     * Created at 2021/12/8 09:55
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $buyerUserId
     * @param int $goodsId
     * @param int $toUserId
     * @throws PublicException|\Throwable
     */
    public function buy(int $buyerUserId, int $goodsId, int $toUserId = 0)
    {
        $goods = $this->checkGoods($buyerUserId, $goodsId, $toUserId);
        $cacheKey = 'BUY:COOL:NUMBER:' . $goodsId;
        if (!redis_lock($cacheKey)) {
            throw new PublicException('请求频次过快，请稍后重试');
        }

        try {
            DB::beginTransaction();
            $expiryTime = time() + $goods['effective_time'];// 过期时间,单位：Unix时间戳
            $orderUserId = $toUserId ?: $buyerUserId;
            $this->modelOrderLog->insertSingle(['user_id' => $orderUserId, 'goods_id' => $goodsId, 'uuid' => $goods['uuid'],
                'expiry_time' => $expiryTime, 'giver_user_id' => $buyerUserId == $orderUserId ? 0 : $buyerUserId, 'created_at' => time(), 'updated_at' => time()]);
            $where = 'user_id=' . $orderUserId . ' and uuid="' . $goods['uuid'] . '"';
            if ($this->modelOrder->getTotalNumberOfQueryRaw($where)) {// 更新时长
                $this->modelOrder->singleUpdateRaw($where, ['goods_id' => $goodsId, 'expiry_time' => $expiryTime, 'updated_at' => time(), 'is_show' => Order::IS_SHOW_YES]);
            } else {
                $orderData = ['user_id' => $orderUserId, 'goods_id' => $goodsId, 'uuid' => $goods['uuid'],
                    'expiry_time' => $expiryTime, 'created_at' => time(), 'updated_at' => time()];
                $this->modelOrder->insertSingle($orderData);// 订单数据
            }

            $this->modelUserScore->inc($buyerUserId, UserScoreStream::FROM_BUY_COOL_NUMBER, 0 - $goods['price']);
            $affectRow = $this->modelGoods->singleUpdate(['id' => $goodsId, 'user_can_buy' => ShoppingMallGoods::USER_CAN_BUY_YES], [
                'user_can_buy' => ShoppingMallGoods::USER_CAN_BUY_NO, 'user_can_buy_time' => $expiryTime,
            ]);
            if (!$affectRow) {
                throw new PublicException('手慢了，已经被别人抢走了~');
            }

            DB::commit();
            redis_unlock($cacheKey);
            // 延时任务，处理靓号过期
            $this->setDelayTaskCallback($orderUserId, $goods['uuid'], $goodsId, $expiryTime - time());
            $this->sendMessage($buyerUserId, $toUserId, $goods);
        } catch (\Throwable $exception) {
            DB::rollBack();
            redis_unlock($cacheKey);
            throw $exception;
        }
    }

    /**
     * Created at 2021/12/23 20:26
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $userId
     * @param string $uuid
     * @param int $goodsId
     * @param int $expiryTime
     */
    public function setDelayTaskCallback(int $userId, string $uuid, int $goodsId, int $expiryTime)
    {
        $this->delayTask('/cool_number/delayed_callback?user_id=' . $userId . '&uuid=' . $uuid
            . '&goods_id=' . $goodsId, $expiryTime);// 延时任务，处理靓号过期
        $pieceDaySecond = 24 * 3600;
        if ($expiryTime > $pieceDaySecond) {
            $this->delayTask('/cool_number/be_overdue_notice?uuid=' . $uuid . '&type=1', $expiryTime - $pieceDaySecond);// 提前一天提醒
        }

        $oneHourSecond = 3600;
        if ($expiryTime > $oneHourSecond) {
            $this->delayTask('/cool_number/be_overdue_notice?uuid=' . $uuid . '&type=2', $expiryTime - $oneHourSecond);// 提前1小时提醒
        }

        $fiveMinutesSecond = 300;
        if ($expiryTime > $fiveMinutesSecond) {
            $this->delayTask('/cool_number/be_overdue_notice?uuid=' . $uuid . '&type=3', $expiryTime - $fiveMinutesSecond);// 提前5分钟提醒
        }
    }

    /**
     * Created at 2021/12/23 16:23
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $buyerUserId
     * @param int $toUserId
     * @param array $goods
     * @return array
     */
    public function getPrivateMsg(int $buyerUserId, int $toUserId, array $goods)
    {
        $buyer = $this->modelUser->get_user($buyerUserId);
        $toUser = $this->modelUser->get_user($toUserId);
        $goodsImage = getFullImageUrl($goods['goods_image']);
        return [
            'gid' => $goods['id'],// 商品id
            'gn' => $goods['goods_name'],// 商品名称
            'gbimg' => $goodsImage,// 商品大图
            'gsimg' => $goodsImage,// 商品小图
            'gres' => '',
            'suid' => $buyerUserId,// 赠送人user_id
            'snn' => $buyer['nickname'],// 赠送人昵称
            'simg' => $buyer['images'][0],// 赠送人头像
            'ruid' => $toUserId,// 接受人user_id
            'rnn' => $toUser['nickname'],// 接受人用户昵称
            'rimg' => $toUser['images'][0],// 接受人头像
        ];
    }

    /**
     * Created at 2021/12/23 15:46
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @param int $buyerUserId
     * @param int $toUserId
     * @param array $goods
     */
    public function sendMessage(int $buyerUserId, int $toUserId, array $goods)
    {
        if ($toUserId) {// 赠送， 发私信
            $data = $this->getPrivateMsg($buyerUserId, $toUserId, $goods);
            $this->servicePrivateMsg->sendPrivateMsg($buyerUserId, $toUserId, 80054, $data, 'kk:send');
            $this->serviceSystemMsg->sendSystemMsgToUserV2($toUserId, 80005, ['n' => $data['snn'] . '送给了你【' . $goods['goods_name'] . '】，快去道具背包查看使用吧~'], 'kk:sys_text_msg');
        } else {// 自己购买
            $data = ['n' => '成功兑换了靓号【' . $goods['goods_name'] . '】，使用期在购买后开始计算，请及时前往【我的】——【背包】——【道具背包】中查看使用~'];
            $this->serviceSystemMsg->sendSystemMsgToUserV2($buyerUserId, 80005, $data, 'kk:sys_text_msg');
        }
    }

    /**
     * Created at 2021/12/13 14:52
     * @Author <yuxiang.zhu@asiainnovations.net>
     * @return array
     */
    public function listUserCanBuyGoods()
    {
        $where = ['user_can_buy' => ShoppingMallGoods::USER_CAN_BUY_YES];
        $total = ShoppingMallGoods::query()->where($where)->count();
        if (!$total) {
            return [];
        }

        $list = ShoppingMallGoods::query()->where($where)->orderByDesc('weight')
            ->orderByDesc('id')->get()->toArray();
        $coolNumbers = collect(CoolNumber::query()->select(['id', 'uuid'])
            ->whereIn('id', array_column($list, 'cool_number_id'))->get()->toArray())->keyBy('id')->toArray();
        foreach ($list as &$item) {
            $item['uuid'] = $coolNumbers[$item['cool_number_id']]['uuid'] ?? '';
        }

        return $list;
    }
}